package utils

import (
	. "arc_srv4/common"
	"arc_srv4/database"
	. "arc_srv4/logutils"
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"go.uber.org/zap"
	"strconv"
	"time"
)

var Pool *redis.Pool

func RedisConnect(ip string, port int, password string, db int) (redis.Conn, error) {
	c, err := redis.Dial(
		"tcp", ip+":"+strconv.Itoa(port),
		redis.DialConnectTimeout(5*time.Second),
		redis.DialReadTimeout(1*time.Second),
		redis.DialWriteTimeout(1*time.Second),
		redis.DialPassword(password),
		redis.DialKeepAlive(1*time.Second),
		redis.DialDatabase(db),
	)
	return c, err
}

func RedisPool(ip string, port int, password string, db int) *redis.Pool {
	maxActive := RedisCfg.MaxActive
	maxIdle := RedisCfg.MaxIdle
	timeout := RedisCfg.IdleTimeout

	return &redis.Pool{
		Dial:         func() (redis.Conn, error) { return RedisConnect(ip, port, password, db) },
		TestOnBorrow: nil,
		MaxIdle:      maxIdle,   //定义redis连接池中最大的空闲链接数
		MaxActive:    maxActive, //在给定时间已分配的最大连接数(限制并发数)
		IdleTimeout:  time.Duration(timeout) * time.Second,
		Wait:         false,
	}
}

//测试是否通畅
func InitRedis() error {
	ip := RedisCfg.IP
	port := RedisCfg.Port
	passWord := RedisCfg.Password
	db := RedisCfg.Db
	Pool = RedisPool(ip, port, passWord, db)
	conn := Pool.Get()
	defer conn.Close()

	r, err := redis.String(conn.Do("PING", "test"))
	if err != nil {
		Logger.Error("redisPool do error.", zap.String("error", err.Error()))
		return err
	}
	if r != "test" {
		Logger.Error("redis connect failed", zap.String("PING", "test"))
	} else {
		Logger.Info("redis connect success", zap.String("PING", "test"))
	}
	return nil
}

func RedisExists(key string) bool {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()

	if conn == nil {
		Logger.Error("redis init failed")
		return false
	}
	n, err := redis.Int(conn.Do("EXISTS", key))
	if err != nil {
		Logger.Error("redis exists failed", zap.String("error", err.Error()))
		return false
	}
	return n > 0
}

func RedisSet(key string, value string, ttl int64) bool {
	//exists := RedisExists(key)
	conn := Pool.Get()
	defer conn.Close()
	//if exists {
	//	return false
	//}
	var err error
	if ttl != -1 {
		_, err = redis.String(conn.Do("set", key, value, "ex", ttl))
	} else {
		_, err = redis.String(conn.Do("set", key, value))
	}
	if err != nil {
		Logger.Error("redis set key value error", zap.String("key", key), zap.String("value", value))
		return false
	}
	return true
}

func RedisGet(key string) []byte {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()
	res, err := conn.Do("get", key)
	if err != nil {
		return nil
	}
	if result, ok := res.([]byte); ok {
		return result
	}
	return []byte{}
}

func RedisTTL(key string) int64 {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()
	ttl, err := redis.Int(conn.Do("ttl", key))
	if err != nil {
		Logger.Error("ttl time out test failed", zap.String("error", err.Error()))
	}
	return int64(ttl)
}

func LoadFaceData() {
	res := QueryAllFaces()
	if res == nil {
		return
	}

	for _, v := range res {
		faceData := new(FaceData)
		faceData.Id = v["id"]
		faceData.ReaderId = v["readerId"]
		faceData.ReaderName = v["readerName"]
		faceData.ModifyTime = v["modifyTime"]
		faceData.Photo = v["face_data"]
		faceData.Valid = StringToBool(v["valid"])
		value, _ := json.Marshal(faceData)

		RedisSet("face_"+v["id"], string(value), -1)
		//print("redisset:",v["id"],"   ",string(value),"\r\n")
	}

}

func RedisDeleteFace() {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()

	keys, _ := redis.Values(conn.Do("KEYS", "face_*"))

	var err error
	if len(keys) > 0 {
		_, err = conn.Do("DEL", keys...)
	}
	if err != nil {
		Logger.Error("RedisDeleteFace failed", zap.String("error", err.Error()))
		panic("RedisDeleteFace failed")
	}
}

func RedisList(match string) ([]interface{}, error) {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()

	keys, err := redis.Values(conn.Do("KEYS", match+"_*"))
	return keys, err
}

func RedisDelete(keys []interface{}) error {
	if Pool == nil {
		_ = InitRedis()
	}
	conn := Pool.Get()
	defer conn.Close()

	var err error
	if len(keys) > 0 {
		_, err = conn.Do("DEL", keys...)
	}
	if err != nil {
		Logger.Error("RedisDelete failed", zap.String("error", err.Error()))
		return err
	}
	return nil
}

// 查所有人脸数据
func QueryAllFaces() []map[string]string {
	// 提取数据库信息
	sql := fmt.Sprintf("select photo.id as id,readerId,readerName,photo,face_data,valid,modifyTime " +
		"from t_user_photo photo " +
		"left join t_branch_equipment eq on photo.branchCode =eq.branch_code " +
		"where valid=1 order by photo.modifyTime desc ")

	res, err := database.Db.Engine.QueryString(sql)
	if err != nil {
		Logger.Error("查询所有人脸数据失败.", zap.String("error", err.Error()))
		return nil
	}
	return res
}

func QueryFacesFromRedis() []FaceData {
	// 提取数据库信息
	conn := Pool.Get()
	defer conn.Close()

	var result []FaceData

	keys, _ := redis.Values(conn.Do("KEYS", "face_*"))

	for _, key := range keys {
		var faceData FaceData
		b, err := redis.Bytes(conn.Do("get", key))
		if err != nil {
			Logger.Error("QueryFacesFromRedis failed.", zap.String("error", err.Error()))
			return nil
		}

		err = json.Unmarshal(b, &faceData)
		if err != nil {
			Logger.Error("json.Unmarshal failed.", zap.String("error", err.Error()))
			continue
		}
		result = append(result, faceData)
	}

	return result
}
